/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 *
 * The Initial Developer of the Original Code is iSQL-Viewer, A Mutli-Platform Database Tool.
 * Portions created by Mark A. Kobold are Copyright (C) 2000-2007. All Rights Reserved.
 *
 * Contributor(s): 
 *  Mark A. Kobold [mkobold <at> isqlviewer <dot> com].
 *  
 * If you didn't download this code from the following link, you should check
 * if you aren't using an obsolete version: http://www.isqlviewer.com
 */
package org.isqlviewer.model;

import java.sql.SQLException;

import javax.swing.event.TreeModelEvent;
import javax.swing.tree.TreePath;

import org.isqlviewer.bookmarks.BookmarkFolder;
import org.isqlviewer.bookmarks.BookmarkReference;
import org.isqlviewer.sql.embedded.EmbeddedDatabase;
import org.isqlviewer.swing.AbstractTreeModel;

/**
 * Datamodel for managing Bookmark objects similar to a local-filesystem.
 * <p>
 * This model mimics a file-system such that there are folders and bookmarks. This model provides various utility
 * methods for creating paths and adding bookmarks. The filesystem if will is based of an internal hashmap of
 * fully-qualified paths as the key(s) and for each path an array list of full-paths as sub paths and Bookmark object(s)
 * represent a folder in a logical sense.
 * <p>
 * In terms of paths they are of the form '/my folder/sub-1/sub-2/' using '/' is obviously always the root-path as well
 * as the root-node of this tree model.
 * <p>
 * This object provides it's own persistence methods to ensure that this model is properly encoded in UTF-8 for XML
 * format. iSQL-Viewer will store a 'bookmarks.xml' file in the designated $isql.home property. The persistence
 * mechanisims ensure UTF8 format by using Charset object of the nio packages.
 * 
 * @see java.nio.charset.Charset
 * @author Markus A. Kobold &lt;mkobold at sprintpcs dot com&gt;
 * @version 1.0
 */
public class BookmarkTreeModel extends AbstractTreeModel {

    private BookmarkFolder rootFolder = null;

    /**
     * @param rootFolder
     */
    public BookmarkTreeModel(BookmarkFolder rootFolder) {

        this.rootFolder = rootFolder;
    }

    public Object getChild(Object parent, int index) {

        if (parent != null && parent instanceof BookmarkFolder) {
            BookmarkFolder folder = (BookmarkFolder) parent;
            return folder.getChild(index);
        }
        return null;
    }

    public int getChildCount(Object parent) {

        if (parent != null && parent instanceof BookmarkFolder) {
            BookmarkFolder folder = (BookmarkFolder) parent;
            return folder.getChildCount();
        }
        return 0;
    }

    public int getIndexOfChild(Object parent, Object child) {

        if (parent != null && parent instanceof BookmarkFolder) {
            BookmarkFolder folder = (BookmarkFolder) parent;
            return folder.indexOfChild(child);
        }
        return 0;
    }

    public Object getRoot() {

        return rootFolder;
    }

    public boolean isLeaf(Object node) {

        return (node == null || node instanceof BookmarkReference);
    }

    public void valueForPathChanged(TreePath path, Object newValue) {

        System.out.println("path:" + path + "; " + newValue);
        Object changedObject = path.getLastPathComponent();
        String changedName = newValue.toString();
        EmbeddedDatabase database = EmbeddedDatabase.getSharedInstance();
        if (changedObject instanceof BookmarkReference) {
            BookmarkReference reference = (BookmarkReference) changedObject;
            String previousName = reference.getName();
            try {
                reference.setName(changedName);
                database.updateBookmark(reference);
            } catch (SQLException e) {
                reference.setName(previousName);
            }
        } else if (changedObject instanceof BookmarkFolder) {
            BookmarkFolder folder = (BookmarkFolder) changedObject;
            String previousName = folder.getName();
            String existingPath = folder.getPath();
            try {
                folder.setName(changedName);
                String newPath = folder.getPath();
                database.renameBookmarkFolder(existingPath, newPath);
            } catch (SQLException e) {
                folder.setName(previousName);
            }
        }
    }

    public void removeBookmark(BookmarkReference bookmark) {

        BookmarkFolder parentFolder = rootFolder.findChildPath(bookmark.getPath());
        parentFolder = (parentFolder == null) ? rootFolder : parentFolder;

        Object[] objectPath = BookmarkFolder.getPathElements(parentFolder);
        Object[] children = new Object[]{bookmark};
        int[] indicies = new int[]{parentFolder.indexOfChild(bookmark)};
        parentFolder.removeBookmark(bookmark);

        TreeModelEvent removeEvent = new TreeModelEvent(this, objectPath, indicies, children);
        fireTreeNodesRemoved(removeEvent);
    }

    public void removeBookmarkFolder(BookmarkFolder folder) {

        BookmarkFolder parentFolder = folder.getParentFolder();
        parentFolder = (parentFolder == null) ? rootFolder : parentFolder;

        Object[] objectPath = BookmarkFolder.getPathElements(parentFolder);
        Object[] children = new Object[]{folder};
        int[] indicies = new int[]{parentFolder.indexOfChild(folder)};
        parentFolder.removeFolder(folder);

        TreeModelEvent removeEvent = new TreeModelEvent(this, objectPath, indicies, children);
        fireTreeNodesRemoved(removeEvent);
    }

    public void addBookmark(BookmarkReference bookmark, BookmarkFolder parentFolder) {

        parentFolder.addBookmark(bookmark);
        Object[] objectPath = BookmarkFolder.getPathElements(parentFolder);
        Object[] children = new Object[]{bookmark};
        int[] indicies = new int[]{parentFolder.indexOfChild(bookmark)};

        TreeModelEvent addEvent = new TreeModelEvent(this, objectPath, indicies, children);
        fireTreeNodesInserted(addEvent);
    }

    public void addBookmarkFolder(BookmarkFolder parentFolder, String folderName) {

        BookmarkFolder childFolder = parentFolder.addChildFolder(folderName);

        Object[] objectPath = BookmarkFolder.getPathElements(parentFolder);
        Object[] children = new Object[]{childFolder};
        int[] indicies = new int[]{parentFolder.indexOfChild(childFolder)};

        TreeModelEvent removeEvent = new TreeModelEvent(this, objectPath, indicies, children);
        fireTreeNodesInserted(removeEvent);
    }

    public void reload(BookmarkFolder parentFolder, BookmarkReference bookmark) {

        Object[] objectPath = BookmarkFolder.getPathElements(parentFolder);
        Object[] children = new Object[]{bookmark};
        int[] indicies = new int[]{parentFolder.indexOfChild(bookmark)};
        parentFolder.addBookmark(bookmark);

        TreeModelEvent changeEvent = new TreeModelEvent(this, objectPath, indicies, children);
        fireTreeNodesChanged(changeEvent);
    }
}